﻿#include "precomp.h"
#include "jcurveview.h"
#include "private/jchartprivate.h"
#include <QtCharts>

QT_CHARTS_USE_NAMESPACE

// - class JCurveViewPrivate -

class JCurveViewPrivate
{
    J_DECLARE_PUBLIC(JCurveView)
    public:
        JCurveViewPrivate(JCurveView *parent) :
      q_ptr(parent),
        axisXType(JCurveView::AxisXInvalid),
        axisX(0),
        axisY(0),
        areaSeries(0),
        series(0)
    {

    }

private:
    JCurveView::AxisXType axisXType;
    QChartView *chartView;
    JCartesianChart *chart;
    QAbstractAxis *axisY;
    QAbstractAxis *axisX;
    QScatterSeries *areaSeries;
    QSplineSeries *series;
    QList<QSplineSeries *> lineSeries;
};

// - class JCurveView -

JCurveView::JCurveView(QWidget *parent) :
    QWidget(parent),
    d_ptr(new JCurveViewPrivate(this))
{
    Q_D(JCurveView);

    QHBoxLayout *horiLayoutMain = new QHBoxLayout(this);
    horiLayoutMain->setContentsMargins(0, 0, 0, 0);

    d->chartView = new QChartView(this);
    horiLayoutMain->addWidget(d->chartView);

    //
    d->chart = new JCartesianChart(/*QChart::ChartTypeCartesian*/);
    d->chartView->setChart(d->chart);

    //
    connect(d->chart, &JCartesianChart::doubleClicked, this, &JCurveView::doubleClicked);

    //
    init();
}

JCurveView::~JCurveView()
{
    delete d_ptr;
}

bool JCurveView::init()
{
    Q_D(JCurveView);

    //
    d->chartView->setRenderHint(QPainter::Antialiasing);
    d->chartView->setBackgroundBrush(QBrush(QColor("#333")));

    //
    //d->chart->setTitle("Zoom in/out example");
    d->chart->setTheme(QChart::ChartThemeBlueCerulean);

    d->series = new QSplineSeries();
    d->chart->addSeries(d->series);

    QValueAxis *axisX = new QValueAxis;
    axisX->setRange(0, 1000);
    axisX->setLabelFormat("%i");
    axisX->setTitleText("Samples");

    QValueAxis *axisY = new QValueAxis;
    axisY->setRange(-1000, 1000);
    axisY->setTitleText("Audio level");

    d->chart->setAxisX(axisX, d->series);
    d->chart->setAxisY(axisY, d->series);

    //d->chart->createDefaultAxes();

    //
    //setAxisXType(AxisXValue);

    // axisY
    //d->axisY = new QValueAxis();
    //d->chart->setAxisY(d->axisY, d->series);

#if 0

    d->areaSeries = new QScatterSeries(this);
    d->areaSeries->setName("选择区域");
    d->areaSeries->setMarkerShape(QScatterSeries::MarkerShapeRectangle);
    d->areaSeries->setMarkerSize(50.0);
    d->chart->addSeries(d->areaSeries);
    //d->areaSeries->attachAxis(d->chart->axisX());
    //d->areaSeries->attachAxis(d->chart->axisY());

    QPen pen(QColor(200, 200, 255, 100));
    pen.setWidth(3);
    d->areaSeries->setPen(pen);

    //TEST

    QVector<QPointF> points;
    for (int i = 0; i < 500; i++) {
        QPointF p((qreal) i, qSin(M_PI / 50 * i) * 100);
        p.ry() += qrand() % 20;
        if ((i % 50) == 0) {
            points.append(p);
            //d->areaSeries->append(i, p.y());
        }
    }

   // d->chart->axisX()->setRange(points.first().x(), points.last().x());
    //d->chart->axisY()->setRange(points.first().y(), points.last().y());

#endif

    return true;
}

JCurveView::AxisXType JCurveView::axisType() const
{
    Q_D(const JCurveView);
    return d->axisXType;
}

void JCurveView::setAxisXType(JCurveView::AxisXType type)
{
    Q_D(JCurveView);

    if (type == d->axisXType) {
        return;
    }

    //
    if (d->axisX != 0) {
        d->chart->removeAxis(d->axisX);
    }

    //
    d->axisXType = type;
    switch (type) {
    case AxisXDateTime:
    {
        QDateTimeAxis *axisX = new QDateTimeAxis();
        axisX->setTickCount(10);
        axisX->setFormat("hh:mm:ss:zzz");

        //
        d->axisX = axisX;
        d->chart->setAxisX(d->axisX, d->series);
        break;
    }
    case AxisXValue:
    {
        QValueAxis *axisX = new QValueAxis();

        //
        d->axisX = axisX;
        d->chart->setAxisX(d->axisX, d->series);
        break;
    }
    default:
        break;
    }
}

void JCurveView::clearCurve()
{
    Q_D(JCurveView);
    QListIterator<QSplineSeries *> citer(d->lineSeries);
    while (citer.hasNext()) {
        d->chart->removeSeries(citer.next());
    }

    d->series->clear();
}

bool JCurveView::appendCurve(const QList<QVariantList> &data)
{
    Q_D(JCurveView);
    Q_UNUSED(data);
    Q_UNUSED(d);
    return true;
}

bool JCurveView::appendCurve(const QVariantList &data)
{
    Q_D(JCurveView);
    Q_UNUSED(data);
    Q_UNUSED(d);
    return true;
}

bool JCurveView::appendCurve(const QString &name, const QList<QPair<QTime, qreal> > &data)
{
    Q_D(JCurveView);
#if 0
    //
    QSplineSeries *series = new QSplineSeries();
    series->setName(name);
    series->setPointsVisible();

    //
    QListIterator<QPair<QTime, qreal> > citer(data);
    while (citer.hasNext()) {
        const QPair<QTime, qreal> &item = citer.next();
        series->append(QPointF(item.first.msecsSinceStartOfDay(), item.second));
    }

    //
    d->chart->addSeries(series);
    series->attachAxis(d->axisX);
    series->attachAxis(d->axisY);
    //
    d->lineSeries.append(series);
#else
    d->series->setName(name);
    //d->series->setPointsVisible();

    //
    QDate currentDate = QDate::currentDate();
    QVector<QPointF> points;
    QListIterator<QPair<QTime, qreal> > citer(data);
    int i = 0;
    while (citer.hasNext()) {
        const QPair<QTime, qreal> &item = citer.next();
        //points.append(QPointF(item.first.msecsSinceStartOfDay(), item.second));
        //d->series->append(QPointF(item.first.msecsSinceStartOfDay(), item.second));
        //d->series->append(QPointF(i++, qrand() % 1000));
        Q_UNUSED(item);
        points.append(QPointF(i+=2, qrand() % 1000));
    }
    d->series->replace(points);

    //d->chart->axisX()->setRange(points.first().x(), points.last().x());
    //d->chart->axisY()->setRange(points.first().y(), points.last().y());
#endif

    return true;
}
